package ca.seia.comp6521.a2.itemsetstorage;

import gnu.trove.map.TIntIntMap;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import ca.seia.comp6521.a2.io.DataFileWriter;
import ca.seia.comp6521.a2.itemsetalgorithms.CandidateGenerator;

/**
 * @author itoe
 *
 */
public class DynamicTriangularMatrix extends TriangularMatrix {

		private TIntIntMap remappedIdMap;
		private TIntIntMap reversedIdMap;
		
		public DynamicTriangularMatrix(TIntIntMap remappedIdMap,TIntIntMap reversedIdMap,int nbr) {
			super(nbr);
			this.remappedIdMap = remappedIdMap;
			this.reversedIdMap = reversedIdMap;
		}
		
		public DynamicTriangularMatrix(TIntIntMap remappedIdMap,int nbr) {
			super(nbr);
			this.remappedIdMap = remappedIdMap;
		}
		
		public DynamicTriangularMatrix(int nbr) {
			super(nbr);
		}
		
		@Override
		public int getIndexOfPair(int value1, int value2) {
			int index1 = remappedIdMap.get(value1);
			int index2 = remappedIdMap.get(value2);
			return super.getIndexOfPair(index1, index2);
		}
		
		public List<IntPair> generateFrequentPairs(int support) {
			List<IntPair> frequentPairs = new ArrayList<>();
//			for (int itemIndex1 = 0; itemIndex1 < this.nbr; itemIndex1++) {
//				for (int itemIndex2 = itemIndex1 + 1; itemIndex2 < this.nbr; itemIndex2++) {
//					try {
//						int pairCount = getPairCount(itemIndex1, itemIndex2);
//						if (pairCount >= support) {
//							frequentPairs.add(new IntPair(itemIndex1, itemIndex2));
//						}
//					} catch (IndexOutOfBoundsException ex) {
//						
//						System.out.println("error for index1 " + itemIndex1);
//						System.out.println("error for index2 " + itemIndex2);
//						System.out.println("Index of pair was " + this.getIndexOfPair(itemIndex1, itemIndex1));
////						ex.printStackTrace();
//					}
//	
//				}
//			}
			for (int itemIndex1 = 0; itemIndex1 < this.nbr; itemIndex1++) {
				for (int itemIndex2 = itemIndex1 + 1; itemIndex2 < this.nbr; itemIndex2++) {
					try {
						int pairCount = getPairCount(itemIndex1, itemIndex2);
						if (pairCount >= support) {
//							System.out.println("adding (" + itemIndex1 + " ,  " + itemIndex2 + " )");
//							System.out.println("should be");
//							System.out.println("adding (" + itemIndex1 + " ,  " + itemIndex2 + " )");
//							frequentPairs.add(new IntPair(itemIndex1, itemIndex2));
							frequentPairs.add(new IntPair(reversedIdMap.get(itemIndex1), reversedIdMap.get(itemIndex2)));
						}
					} catch (IndexOutOfBoundsException ex) {
						
						System.out.println("error for index1 " + itemIndex1);
						System.out.println("error for index2 " + itemIndex2);
						System.out.println("Index of pair was " + this.getIndexOfPair(itemIndex1, itemIndex1));
//						ex.printStackTrace();
					}
				}
			}
			return frequentPairs;
		}
		
		public void writeToDisk(List<IntPair> frequentPairs, DataFileWriter fileWriter) throws IOException {
			for(IntPair intPair: frequentPairs) {
				
				fileWriter.writeItems(intPair,this.getPairCount(remappedIdMap.get(intPair.getValOne()), remappedIdMap.get(intPair.getValTwo())));
//				fileWriter.writeItems(intPair,this.getPairCount(intPair.getValOne(), intPair.getValTwo()));
			}
		}
		
		public void writeToDisk(int support, DataFileWriter fileWriter) throws IOException {
			
			for(int itemIndex1 = 0 ; itemIndex1 < this.nbr ; itemIndex1++) {
				for(int itemIndex2 = itemIndex1+1 ; itemIndex2 < this.nbr ; itemIndex2++) {
					int pairCount = getPairCount(itemIndex1, itemIndex2);
					if(pairCount >= support) {
//						fileWriter.writeItems(itemIndex1,itemIndex2,pairCount);
						
						fileWriter.writeItems(itemIndex1,itemIndex2,pairCount);
					}
				}
			}
		}
		
		public List<IntItems> generateCandidateTriplets(List<IntPair> frequentPairs) {
			
			List<IntItems> triplets = new ArrayList<IntItems>(60000);
			
			int keyLength = frequentPairs.size();
			for(int keyIndex = 0 ; keyIndex < keyLength ; keyIndex++) {
				for(int secondPairIndex = keyIndex + 1; secondPairIndex < keyLength ; secondPairIndex++) {
//					System.out.println("size of triplets " + triplets.size());
					IntItems triplet = IntItems.generateCandidateTriplet(frequentPairs.get(keyIndex), frequentPairs.get(secondPairIndex));
					if(triplet == null) {
						break;
					} else {
						triplets.add(triplet);
					}
				}
			}
			return triplets;
		}
		
		public List<IntTriplet> generateCandidateIntTriplets(List<IntPair> frequentPairs) {
			
			List<IntTriplet> triplets = new ArrayList<IntTriplet>(60000);
			
			int keyLength = frequentPairs.size();
			for(int keyIndex = 0 ; keyIndex < keyLength ; keyIndex++) {
				for(int secondPairIndex = keyIndex + 1; secondPairIndex < keyLength ; secondPairIndex++) {
//					System.out.println("size of triplets " + triplets.size());
					IntTriplet triplet = CandidateGenerator.generateCandidateIntTriplet(frequentPairs.get(keyIndex), frequentPairs.get(secondPairIndex));
					if(triplet == null) {
						break;
					} else {
						triplets.add(triplet);
					}
				}
			}
			return triplets;
		}
		
		public List<CharTriplet> generateCandidateCharTriplets(List<IntPair> frequentPairs) {
			
			List<CharTriplet> triplets = new ArrayList<CharTriplet>(60000);
			
			int keyLength = frequentPairs.size();
			for(int keyIndex = 0 ; keyIndex < keyLength ; keyIndex++) {
				for(int secondPairIndex = keyIndex + 1; secondPairIndex < keyLength ; secondPairIndex++) {
//					System.out.println("size of triplets " + triplets.size());
					CharTriplet triplet = CandidateGenerator.generateCandidateCharTriplet(frequentPairs.get(keyIndex), frequentPairs.get(secondPairIndex));
					if(triplet == null) {
						break;
					} else {
						triplets.add(triplet);
					}
				}
			}
			return triplets;
		}
		
		
		public Set<IntItems> generateCandidateTripletsWithNoDuplicates(List<IntPair> frequentPairs) {
			
			Set<IntItems> triplets = new HashSet<IntItems>(60000);
			
			int keyLength = frequentPairs.size();
			for(int keyIndex = 0 ; keyIndex < keyLength ; keyIndex++) {
				for(int secondPairIndex = keyIndex + 1; secondPairIndex < keyLength ; secondPairIndex++) {
//					System.out.println("size of triplets " + triplets.size());
					IntItems triplet = IntItems.generateCandidateTriplet(frequentPairs.get(keyIndex), frequentPairs.get(secondPairIndex));
					if(triplet == null) {
						break;
					} else {
						triplets.add(triplet);
					}
				}
			}
			return triplets;
		}

		@Override
		public String toString() {
			return "DynamicTriangularMatrix [remappedIdMap=" + remappedIdMap + ", size=" + size + ", nbr=" + nbr + ", counts=" + Arrays.toString(counts) + "]";
		}
		
		
}
